package com.openNetty.common.utils;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * 读取大文件
 *
 * @author zhenggm
 * @version 1.0.0
 */
public class MappedBiggerFileReader {
    private MappedByteBuffer[] mappedBufArray;
    private int count = 0;
    private int number;
    private FileInputStream fileIn;
    private long fileLength;
    private int arraySize;
    private byte[] array;
    private int limit;
    private int position;


    public MappedBiggerFileReader(String fileName, int arraySize, int count, int position) throws IOException {
        this.fileIn = new FileInputStream(fileName);
        FileChannel fileChannel = fileIn.getChannel();
        this.fileLength = fileChannel.size();
        this.number = (int) Math.ceil((double) fileLength / (double) Integer.MAX_VALUE);
        this.mappedBufArray = new MappedByteBuffer[number];// 内存文件映射数组
        long preLength = 0;
        long regionSize = (long) Integer.MAX_VALUE;// 映射区域的大小
        for (int i = 0; i < number; i++) {// 将文件的连续区域映射到内存文件映射数组中
            if (fileLength - preLength < (long) Integer.MAX_VALUE) {
                regionSize = fileLength - preLength;// 最后一片区域的大小
            }
            mappedBufArray[i] = fileChannel.map(FileChannel.MapMode.READ_ONLY, preLength, regionSize);
            preLength += regionSize;// 下一片区域的开始
        }
        this.arraySize = arraySize;
        this.count = count;
        this.position = position;
    }

    public int read() throws IOException {
        try {
            if (count >= number) {
                return -1;
            }
            mappedBufArray[count].position(position);
            limit = mappedBufArray[count].limit();
            position = mappedBufArray[count].position();
            if (limit - position > arraySize) {
                array = new byte[arraySize];
                mappedBufArray[count].get(array);
                position = mappedBufArray[count].position();
                return arraySize;
            } else {// 本内存文件映射最后一次读取数据
                array = new byte[limit - position];
                mappedBufArray[count].get(array);
                int pos = mappedBufArray[count].position();
                if (count < number) {
                    count++;// 转换到下一个内存文件映
                    position = 0;
                }
                return limit - pos;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }

    public void close() throws IOException {
        fileIn.close();
        array = null;
    }

    public byte[] getArray() {
        return array;
    }

    public long getFileLength() {
        return fileLength;
    }

    /**
     * 返回已经读取的位置
     *
     * @return
     */
    public int getCount() {
        return count;
    }

    public int getPosition() {
        return position;
    }

    public static void main(String[] args) throws IOException {
        FileOutputStream os = new FileOutputStream("E:\\1.zip");
        MappedBiggerFileReader reader = new MappedBiggerFileReader("E:\\22.zip", 65536, 0, 0);
        long start = System.currentTimeMillis();
        while (reader.read() != -1) {
            os.write(reader.getArray());
        }
        long end = System.currentTimeMillis();
        reader.close();
        System.out.println("MappedBiggerFileReader: " + (end - start));
    }
}
